package com.mybatis.util;

import com.mybatis.entity.PField;
import com.mybatis.entity.PTable;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.Map;

public final class SQLUtil {
    public static final Class<? extends Annotation> PFIELD = PField.class;
    public static final Class<? extends Annotation> PTABLE = PTable.class;

    public static void main(String[] args) throws Exception {
    }

    public static String deleteEntity(Class<?> clazz, Object obj) throws Exception {
        String fieldName;
        StringBuilder sql = new StringBuilder();
        String idName = getTableKeyName(clazz);
        sql.append("DELETE FROM " + getTableName(clazz));
        sql.append("  WHERE 1=1 ");
        if (obj == null) {
            sql.append(" AND " + getColumnName(clazz.getDeclaredField(idName)) + " = #{" + idName + "},");
        } else if (obj == null || !(obj instanceof Map)) {
            throw new Exception("不支持该类型参数.");
        } else {
            Field[] files = clazz.getDeclaredFields();
            Map map = (Map) obj;
            for (Field filed : files) {
                if ((map == null || map.containsKey(filed.getName())) && (fieldName = getColumnName(filed)) != null) {
                    if (MybatisHelper.getJdbcType(filed, map).equalsIgnoreCase("")) {
                        sql.append(" AND " + fieldName + " = #{" + fieldName).append("} ");
                    } else {
                        sql.append(" AND " + fieldName + " IS NULL");
                    }
                }
            }
        }
        return sql.subSequence(0, sql.length() - 1).toString();
    }

    public static String deleteEntityBatch(Class<?> clazz, StringBuilder first) throws Exception {
        Field field = clazz.getDeclaredField(getTableKeyName(clazz));
        first.append("DELETE FROM " + getTableName(clazz));
        first.append("  WHERE  ").append(getColumnName(field)).append(" IN ");
        return first.toString();
    }

    public static String selectEntityBatch(Class<?> clazz) throws Exception {
        StringBuilder first = new StringBuilder(100);
        Field field = clazz.getDeclaredField(getTableKeyName(clazz));
        first.append("SELECT ").append(getReturnStr(clazz)).append(" FROM  ").append(getTableName(clazz));
        first.append("  WHERE  ").append(getColumnName(field)).append(" IN ");
        return first.toString();
    }

    public static String updateEntityById(Class<?> clazz, Object args) throws Exception {
        String fieldName;
        StringBuilder sql = new StringBuilder();
        StringBuilder set = new StringBuilder();
        StringBuilder wheresql = new StringBuilder();
        String idName = getTableKeyName(clazz);
        sql.append("UPDATE  ").append(getTableName(clazz));
        Map<String, Object> map = null;
        if (args != null && (args instanceof Map)) {
            map = (Map) args;
            if (!map.containsKey(idName) || map.get(idName) == null) {
                throw new Exception("Map中必须包括ID字段并且值非空.");
            }
        } else if (args == null || args.getClass() != clazz) {
            throw new Exception("不支持该类型参数.");
        } else {
            Field keyField = clazz.getDeclaredField(idName);
            keyField.setAccessible(true);
            if (keyField.get(args) == null) {
                throw new Exception("实体中ID字段值必须非空.");
            }
        }
        set.append(" SET ");
        wheresql.append(" WHERE 1=1 ");
        Field[] files = clazz.getDeclaredFields();
        for (Field filed : files) {
            if (idName.equalsIgnoreCase(filed.getName())) {
                wheresql.append(" AND ").append(getColumnName(filed)).append(" = #{").append(idName).append("},");
            } else if ((map == null || map.containsKey(filed.getName())) && (fieldName = getColumnName(filed)) != null) {
                set.append(String.valueOf(fieldName) + " = #{" + filed.getName()).append(MybatisHelper.getJdbcType(filed, map)).append("} ,");
            }
        }
        if (wheresql.equals(" WHERE 1=1 ")) {
            throw new RuntimeException("实体变量没有设置ID字段值");
        }
        sql.append(set.substring(0, set.length() - 1)).append(wheresql.substring(0, wheresql.length() - 1));
        return sql.toString();
    }

    public static String findEntity(Class<?> clazz, Object args) throws Exception {
        String columnName;
        StringBuilder sql = new StringBuilder();
        StringBuilder whereSQL = new StringBuilder(" WHERE 1=1 ");
        StringBuffer orderby = new StringBuffer();
        sql.append("SELECT ").append(getReturnStr(clazz)).append(" FROM  ").append(getTableName(clazz));
        Object param = args;
        if (param == null) {
            sql.append((CharSequence) whereSQL);
        } else if (param instanceof Map) {
            Map<String, Object> map = (Map) param;
            if (map.containsKey("orderby")) {
                orderby.append(" ORDER BY " + getColumnName(clazz.getDeclaredField((String) map.get("orderby"))));
            }
            if (map.containsKey("sortby")) {
                orderby.append(" " + ((String) map.get("sortby")) + " ");
            }
            for (String key : map.keySet()) {
                if (!"orderby".equalsIgnoreCase(key) && !"sortby".equalsIgnoreCase(key) && (columnName = getColumnName(clazz.getDeclaredField(key))) != null) {
                    if (!map.containsKey(key) || map.get(key) != null) {
                        whereSQL.append(" AND ").append(columnName).append(" = #{" + key).append("} ");
                    } else {
                        whereSQL.append(" AND ").append(columnName).append(" IS NULL ");
                    }
                }
            }
            sql.append(whereSQL.subSequence(0, whereSQL.length() - 1)).append(orderby);
        } else if (param.getClass() == clazz) {
            Field[] files = clazz.getDeclaredFields();
            for (Field filed : files) {
                String columnName2 = getColumnName(filed);
                if (columnName2 != null) {
                    filed.setAccessible(true);
                    if (filed.get(param) != null) {
                        whereSQL.append(" AND ").append(columnName2).append(" = #{" + filed.getName()).append("}");
                    }
                }
            }
            sql.append(whereSQL.subSequence(0, whereSQL.length()));
        } else if (param.getClass() == String.class) {
            String fieldName = (String) param;
            String columnName3 = getColumnName(clazz.getDeclaredField(fieldName));
            if (columnName3 != null) {
                whereSQL.append(" AND ").append(columnName3).append(" = #{" + fieldName).append("}");
            }
            sql.append(whereSQL.subSequence(0, whereSQL.length()));
        }
        return sql.toString();
    }

    public static String insertEntityBatch(Class<?> clazz, boolean isBatch, StringBuilder sql, StringBuilder after) {
        if (!isBatch) {
            sql = new StringBuilder();
            after = new StringBuilder();
        }
        sql.append("INSERT INTO ").append(getTableName(clazz));
        Field[] files = clazz.getDeclaredFields();
        StringBuilder intosql = new StringBuilder();
        StringBuilder valuessql = new StringBuilder();
        intosql.append("( ");
        valuessql.append("( ");
        for (Field field : files) {
            String fieldName = getColumnName(field);
            if (fieldName != null) {
                intosql.append(fieldName).append(",");
                valuessql.append("#{");
                if (isBatch) {
                    valuessql.append("item.");
                }
                valuessql.append(String.valueOf(field.getName()) + "},");
            }
        }
        sql.append(intosql.substring(0, intosql.length() - 1)).append(") ").append(" VALUES");
        after.append(valuessql.substring(0, valuessql.length() - 1)).append(") ");
        if (isBatch) {
            return null;
        }
        return String.valueOf(sql.toString()) + after.toString();
    }

    public static String getColumnName(Field field) {
        String feildName;
        if (field == null) {
            return null;
        }
        field.setAccessible(true);
        if (field.isAnnotationPresent(PFIELD)) {
            PField anColumn = (PField) field.getAnnotation(PFIELD);
            if (anColumn.isIgnore()) {
                return null;
            }
            if (anColumn.value().equals("")) {
                feildName = field.getName();
            } else {
                feildName = anColumn.value();
            }
        } else {
            feildName = field.getName();
        }
        return feildName;
    }

    public static String getTableName(Class<?> clazz) {
        String clazzName;
        if (clazz == null) {
            return null;
        }
        if (!clazz.isAnnotationPresent(PTABLE)) {
            clazzName = clazz.getSimpleName();
        } else {
            PTable antable = (PTable) clazz.getAnnotation(PTABLE);
            if (antable.value() == "") {
                clazzName = clazz.getSimpleName();
            } else {
                clazzName = antable.value();
            }
        }
        return clazzName;
    }

    public static String getReturnStr(Class<?> clazz) {
        StringBuilder returnStr = new StringBuilder();
        Field[] fileds = clazz.getDeclaredFields();
        for (Field filed : fileds) {
            String fieldNameReturn = getColumnName(filed);
            if (fieldNameReturn != null) {
                returnStr.append(fieldNameReturn).append(" ");
                if (!fieldNameReturn.equals(filed.getName())) {
                    returnStr.append(" as ").append(filed.getName());
                }
                returnStr.append(",");
            }
        }
        return returnStr.substring(0, returnStr.length() - 1);
    }

    public static String getTableKeyName(Class<?> clazz) {
        if (clazz == null) {
        }
        if (!clazz.isAnnotationPresent(PTABLE)) {
            return PTable.ID_NAME;
        }
        return ((PTable) clazz.getAnnotation(PTABLE)).idName();
    }
}
